#pragma once
#include <iostream>
#include <string>
#include <cassert>
#include <functional>
#include "Epoller.hpp"
#include "Sock.hpp"
#include "Threadpoll.hpp"

using func_t = std::function<std::string (std::string)>;

class EpollServer {
    const static int gnum = 64;
public:
    EpollServer(func_t func, uint16_t port = Config::GetInstance()->GetPort()) : func_(func), port_(port), pool_(6) {}
    void InitServer() {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        epoller_.Create();

        Logger::getInstance().loggger()->info("init server success");
    }
    int Start() {
        // 将listensock添加到epoll中--启用边缘触发模式
        bool r = epoller_.AddEvent(listensock_.Fd(), EPOLLIN | EPOLLET);
        assert(r);
        (void)r;
        // 设置500毫秒以便提升高并发的性能
        int timeout = 500;
        while (true) {
            int n = epoller_.Wait(revs_, gnum, timeout);
            switch (n) {
            case 0:
                // Logger::getInstance().loggger()->debug("timeout...");
                break;
            case -1:
                Logger::getInstance().loggger()->warn("epoll_wait failed");
                break;
            default:
                HandlerEvents(n);
                break;
            }
        }
    }
    void HandlerEvents(int num) {
        for (int i = 0; i < num; i++) {
            int fd = revs_[i].data.fd;
            uint32_t events = revs_[i].events;
            if (events & EPOLLIN) {
                if (fd == listensock_.Fd()) {
                    // 新连接到来
                    std::string clientip;
                    uint16_t clientport;
                    int sock = listensock_.Accept(&clientip, &clientport);
                    if (sock < 0)
                        continue;
                    // 这里，不能进行recv/read,只有epoll知道sock上面的事件情况，将sock添加到epoll中
                    bool r = epoller_.AddEvent(sock, EPOLLIN | EPOLLET);
                    assert(r);
                    (void)r;
                } else {
                    Handler(fd);
                }
            }
        }
    }

    void Handler(int fd) {
        pool_.enqueue([fd, this] {
            std::string request;
            while (true)
            {
                char buffer[1024];
                ssize_t s = recv(fd, buffer, sizeof(buffer) - 1, MSG_DONTWAIT);
                if (s > 0) {
                    buffer[s] = 0;
                    request += buffer;

                    std::string response = func_(request);
                    //响应
                    Logger::getInstance().loggger()->debug("send...");
                    send(fd, response.c_str(), response.size(), 0);
                    break;
                }
                else {
                    if (errno == EAGAIN || errno == EWOULDBLOCK)
                        break;
                    Logger::getInstance().loggger()->debug("recv error, client quit ...");
                    epoller_.DelEvent(fd);
                    close(fd);
                    return;
                }
            }
        });
    }

    ~EpollServer() {
        listensock_.Close();
        epoller_.Close();
    }
private:
    uint16_t port_;
    Sock listensock_;
    Epoller epoller_;
    struct epoll_event revs_[gnum];
    func_t func_;
    ThreadPool pool_;
};